<script setup lang="ts">
import { h, reactive, ref, onMounted } from 'vue'
import { NCard, NTree, NPopover, NPopconfirm, NDivider, NButton, NSpace, NIcon, NForm, NGrid, NFormItemGi, NInput, NInputNumber, NSelect, NTreeSelect, useNotification, useDialog } from 'naive-ui'
import type { FormInst, TreeOption } from 'naive-ui'

import { useDictStore } from '@/stores/dictStore'
import { useIconStore } from '@/stores/iconStore'
import { useMenuStore } from '@/stores/menuStore'
import { useUserStore } from '@/stores/userStore'
import http from '@/tools/http'
import { toTree } from '@/tools/tree'
import type { Tree } from '@/tools/tree'

import { PlusOutlined, DeleteOutlined, AppstoreAddOutlined } from '@vicons/antd'

import RIcon from '@/components/icons/RIcon.vue'

import MenuAuthManage from './menu-auth-manage.vue'

type MenuData = {
    menuCode?: string
    menuName?: string
    menuStatus?: string
    menuType?: string
    loadType?: string
    menuUrl?: string
    menuIcon?: string
    menuSort?: number
    menuParent?: string
    remark?: string
}

const dictStore = useDictStore()
const iconStore = useIconStore()
const menuStore = useMenuStore()
const userStore = useUserStore()
const dialog = useDialog()

const menuSearch = ref("")
let menuTreeData = ref<any>([])
const selectedKeys = ref<string[]>([])

function renderSuffix(info: { option: Tree | TreeOption, checked: boolean, selected: boolean }) {
    return h(
        NSpace, null,
        () => [
            userStore.hasAuth("menu:add") && info.option.data.menuType === '0' ? h(
                NPopover,
                {
                    style: "width: 150px",
                    headerStyle: { padding: 0 },
                    contentStyle: { padding: 0 },
                    placement: "bottom"
                },
                {
                    trigger: () => h(
                        NIcon,
                        {
                            size: 15,
                            style: "line-height: 2em;"

                        },
                        { default: () => h(PlusOutlined) }
                    )
                    ,
                    header: () => h(
                        NButton,
                        {
                            style: "width:100%",
                            quaternary: true,
                            onclick: () => openMenuAdd(info.option.data, true)
                        },
                        () => "添加同级菜单"
                    ),
                    default: () => h(
                        NButton,
                        {
                            style: "width:100%",
                            quaternary: true,
                            onclick: () => openMenuAdd(info.option.data, false)
                        },
                        () => "添加子级菜单"
                    )
                }
            ) : null,
            userStore.hasAuth("menu:delete") ? h(
                NPopconfirm,
                {
                    onPositiveClick: (e: MouseEvent) => deleteMenu()
                },
                {
                    trigger: () => {
                        return h(
                            NIcon,
                            {
                                size: 15,
                                style: "line-height: 2em;",
                                onclick: () => openMenuDelete(info.option.data)
                            },
                            { default: () => h(DeleteOutlined) }
                        )
                    },
                    default: () => { return "确认删除该菜单及下级菜单么？" }
                }
            ) : null
        ]
    )
}

onMounted(() => {
    listMenu(null)
})

const formRef = ref<FormInst | null>(null)
const formData = reactive<MenuData>({
    menuCode: "",
    menuName: "",
    menuStatus: '0',
    menuType: '0',
    loadType: '0',
    menuUrl: "",
    menuIcon: "",
    menuSort: 999,
    menuParent: "",
    remark: ""
})
const formRules = {
    menuCode: {
        required: true,
        message: '请输入菜单编码',
        trigger: ['input']
    },
    menuName: {
        required: true,
        message: '请输入菜单名称',
        trigger: ['input']
    },
    menuType: {
        required: true,
        message: '请输入菜单类型',
        trigger: ['input']
    },
    menuStatus: {
        required: true,
        message: '请输入菜单类型',
        trigger: ['input']
    },
    loadType: {
        required: true,
        message: '请输入加载类型',
        trigger: ['input']
    }
}

const title = ref("")
const currentMenu = ref<MenuData>({})
const currentIcon = ref(AppstoreAddOutlined)

function treeNodeClicked(info: { option: Tree | TreeOption }) {
    return {
        onClick: () => {
            openMenu(info.option.data)
        }
    }
}

function onMenuIconChange(newMenuIcon: string) {
    formData.menuIcon = newMenuIcon
    if (newMenuIcon === null || newMenuIcon === "") {
        currentIcon.value = AppstoreAddOutlined
    }
}

function setIcon(icon: any) {
    formData.menuIcon = icon.name
    currentIcon.value = icon.icon
}

function openMenu(menu: MenuData) {
    title.value = `菜单【${menu.menuName}】信息`
    selectedKeys.value.length = 0
    if (menu.menuCode) {
        selectedKeys.value.push(menu.menuCode)
    }
    currentMenu.value = menu
    if (menu.menuIcon) {
        setIcon(iconStore.icon(menu.menuIcon))
    } else {
        currentIcon.value = AppstoreAddOutlined
    }
    formData.menuCode = menu.menuCode
    formData.menuName = menu.menuName
    formData.menuStatus = menu.menuStatus
    formData.menuType = menu.menuType
    formData.loadType = menu.loadType
    formData.menuUrl = menu.menuUrl
    formData.menuIcon = menu.menuIcon
    formData.menuSort = menu.menuSort
    formData.menuParent = menu.menuParent
    formData.remark = menu.remark
    listMenuAuth()
}

function openMenuAdd(menu: MenuData, sameParent: boolean) {
    title.value = "新增菜单"
    currentIcon.value = AppstoreAddOutlined
    formData.menuCode = ""
    formData.menuName = ""
    formData.menuStatus = '0'
    formData.menuType = '0'
    formData.loadType = '0'
    formData.menuUrl = ""
    formData.menuIcon = ""
    formData.menuSort = 999
    if (menu === null) {
        formData.menuParent = ""
    } else {
        if (sameParent) {
            formData.menuParent = menu.menuParent
        } else {
            formData.menuParent = menu.menuCode
        }
    }
    formData.remark = ""
    menuAuthData.length = 0
}

function openMenuEdit(menu: MenuData) {
    title.value = `菜单【${menu.menuName}】信息 - 编辑`
    formData.menuCode = menu.menuCode
    formData.menuName = menu.menuName
    formData.menuStatus = menu.menuStatus
    formData.menuType = menu.menuType
    formData.loadType = menu.loadType
    formData.menuUrl = menu.menuUrl
    formData.menuIcon = menu.menuIcon
    formData.menuSort = menu.menuSort
    formData.menuParent = menu.menuParent
    formData.remark = menu.remark
}

function openMenuDelete(menu: MenuData) {
    formData.menuCode = menu.menuCode
    formData.menuName = menu.menuName
    formData.menuStatus = menu.menuStatus
    formData.menuType = menu.menuType
    formData.loadType = menu.loadType
    formData.menuUrl = menu.menuUrl
    formData.menuIcon = menu.menuIcon
    formData.menuSort = menu.menuSort
    formData.menuParent = menu.menuParent
    formData.remark = menu.remark
}

function submit() {
    formRef.value?.validate((errors) => {
        if (!errors) {
            dialog.create({
                title: '温馨提示',
                content: '确定提交吗？',
                positiveText: '确定',
                negativeText: '取消',
                onPositiveClick: () => {
                    if (title.value.includes('编辑')) {
                        updateMenu()
                    }
                    if (title.value.includes('新增')) {
                        addMenu()
                    }
                }
            })
        }
    })
}

function listMenu(menu: MenuData | null) {
    http.post("/menu/list").then(({ data }) => {
        if (data.code === "0") {
            const menuList = data.data.filter((item: MenuData) => item.menuType !== '2')
            menuTreeData.value = toTree(menuList, "menuParent", null, "menuCode", "menuName", "menuCode")
            menuStore.refreshMenuList(menuList)
            if (menu === null) {
                openMenu(menuTreeData.value[0].data)
            } else {
                openMenu(menu)
            }
        }
    })
}

const notification = useNotification()

function addMenu() {
    const request = {
        menu: formData,
        btnList: menuAuthData
    }
    http.post("/menu/add", request).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '添加成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            listMenu(formData)
        }
    })
}

function updateMenu() {
    const request = {
        menu: formData,
        btnList: menuAuthData
    }
    http.post("/menu/update", request).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '修改成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            listMenu(formData)
        }
    })
}

function deleteMenu() {
    http.post("/menu/delete", formData).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '删除成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            listMenu(formData)
        }
    })
}

type menuAuthDataType = {
    menuCode?: string
    menuName?: string
}

const menuAuthData = reactive<menuAuthDataType[]>([])

function listMenuAuth() {
    if (currentMenu.value.menuType === '1') {
        const request = {
            menuCode: currentMenu.value.menuCode
        }
        http.post("/menu/btn/list", request).then(({ data }) => {
            if (data.code === "0") {
                menuAuthData.length = 0
                for (let i = 0; i < data.data.length; i++) {
                    const menuAuth = {
                        menuCode: data.data[i].menuCode,
                        menuName: data.data[i].menuName
                    }
                    menuAuthData.push(menuAuth)
                }
            }
        })
    }
}

function addMenuAuth(menuAuth: menuAuthDataType) {
    menuAuthData.push(menuAuth)
}

function editMenuAuth(menuAuth: menuAuthDataType) {
    for (let i = 0; i < menuAuthData.length; i++) {
        if (menuAuthData[i].menuCode === menuAuth.menuCode) {
            menuAuthData[i].menuName = menuAuth.menuName
        }
    }
}

function deleteMenuAuth(menuAuth: menuAuthDataType) {
    for (let i = 0; i < menuAuthData.length; i++) {
        if (menuAuthData[i].menuCode === menuAuth.menuCode) {
            menuAuthData.splice(i, 1)
        }
    }
}
</script>

<template>
    <div class="flame-container">
        <n-card :content-style="{ display: 'flex', padding: '0px' }" :bordered="false">
            <div class="content-left">
                <div class="content-left-top">
                    <n-input v-model:value="menuSearch" type="text" placeholder="输入菜单名称关键字过滤" clearable />
                </div>
                <div class="content-left-content">
                    <n-tree block-line :data="menuTreeData" :pattern="menuSearch" :show-irrelevant-nodes="false"
                        :node-props="treeNodeClicked" :render-suffix="renderSuffix" :selected-keys="selectedKeys" />
                </div>
            </div>
            <div class="content-right">
                <div class="content-right-title">
                    {{ title }}
                </div>
                <div class="content-right-body">
                    <n-form class="content-right-form" ref="formRef" :model="formData" :rules="formRules"
                        :disabled="!title.includes('编辑') && !title.includes('新增')" label-placement="left"
                        label-width="78px" label-align="left" require-mark-placement="left">
                        <n-grid :cols="2" :x-gap="10" :y-gap="0">
                            <n-form-item-gi :span="1" label="菜单编码" path="menuCode">
                                <n-input :disabled="!title.includes('新增')" v-model:value="formData.menuCode"
                                    placeholder="请输入菜单编码" />
                            </n-form-item-gi>
                            <n-form-item-gi :span="1" label="菜单名称" path="menuName">
                                <n-input v-model:value="formData.menuName" placeholder="请输入菜单名称" />
                            </n-form-item-gi>
                            <n-form-item-gi :span="1" label="菜单类型" path="menuType">
                                <n-select v-model:value="formData.menuType" :options="dictStore.dict('MENU_TYPE')"
                                    placeholder="请选择菜单类型" />
                            </n-form-item-gi>
                            <n-form-item-gi :span="1" label="菜单状态" path="menuStatus">
                                <n-select v-model:value="formData.menuStatus" :options="dictStore.dict('MENU_STATUS')"
                                    placeholder="请选择菜单状态" />
                            </n-form-item-gi>
                            <n-form-item-gi :span="2" label="菜单链接" path="menuUrl">
                                <n-input v-model:value="formData.menuUrl" placeholder="请输入菜单链接" clearable />
                            </n-form-item-gi>
                            <n-form-item-gi :span="1" label="菜单图标" path="menuIcon">
                                <n-input v-model:value="formData.menuIcon" placeholder="请输入菜单图标"
                                    :on-change="onMenuIconChange" clearable>
                                    <template #suffix>
                                        <n-popover style="width: 304px;height: 216px;padding: 8px;" placement="bottom"
                                            trigger="click">
                                            <template #trigger>
                                                <r-icon :icon="currentIcon" class-name="menu-icon-suffix-button" />
                                            </template>
                                            <div class="icon-table">
                                                <r-icon v-for="item in iconStore.iconList" :icon="item.icon"
                                                    @click="setIcon(item)" class-name="icon-unit" />
                                            </div>
                                        </n-popover>
                                    </template>
                                </n-input>
                            </n-form-item-gi>
                            <n-form-item-gi :span="1" label="加载类型" path="loadType">
                                <n-select v-model:value="formData.loadType" :options="dictStore.dict('LOAD_TYPE')"
                                    placeholder="请选择菜单状态" />
                            </n-form-item-gi>
                            <n-form-item-gi :span="1" label="上级目录" path="menuParent">
                                <n-tree-select v-model:value="formData.menuParent" :options="menuTreeData"
                                    default-value="" placeholder="请选择上级目录" clearable />
                            </n-form-item-gi>
                            <n-form-item-gi :span="1" label="菜单排序" path="menuSort">
                                <n-input-number v-model:value="formData.menuSort" :min="1" :max="999"
                                    placeholder="请输入菜单排序" style="width:100%" />
                            </n-form-item-gi>
                            <n-form-item-gi :span="2" label="备注" path="remark">
                                <n-input v-model:value="formData.remark" placeholder="请输入备注" clearable />
                            </n-form-item-gi>
                        </n-grid>
                    </n-form>
                    <n-divider v-if="currentMenu.menuType === '1'" style="margin-top:0;margin-bottom:12px;"
                        title-placement="left">功能权限维护</n-divider>
                    <div v-if="currentMenu.menuType === '1'" class="content-right-auth">
                        <menu-auth-manage :disabled="!title.includes('编辑') && !title.includes('新增')"
                            :current-menu="currentMenu" :menu-auth-data="menuAuthData" :add-menu-auth="addMenuAuth"
                            :edit-menu-auth="editMenuAuth" :delete-menu-auth="deleteMenuAuth" />
                    </div>
                </div>
                <div class="content-right-bottom" v-if="userStore.hasAuth('menu:edit')">
                    <n-space>
                        <n-button v-if="!title.includes('编辑') && !title.includes('新增')"
                            @click="openMenuEdit(currentMenu)">
                            编辑
                        </n-button>
                        <n-button v-if="title.includes('编辑') || title.includes('新增')" @click="openMenu(currentMenu)">
                            取消
                        </n-button>
                        <n-button v-if="title.includes('编辑') || title.includes('新增')" @click="submit()">
                            提交
                        </n-button>
                    </n-space>
                </div>
            </div>
        </n-card>
    </div>
</template>

<style scoped>
.content {
    top: 68.8px;
}

.content-left {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    width: 330px;
    border-right: 1px solid var(--n-border-color);
}

.content-left .content-left-top {
    display: flex;
    gap: 3px;
    padding: 5px;
    height: 34px;
}

.content-left .content-left-content {
    height: 100%;
}

.content-right {
    position: absolute;
    top: 0;
    left: 330px;
    right: 0;
    bottom: 0;
    display: flex;
    flex: 1;
    flex-direction: column;
}

.content-right .content-right-body {
    position: absolute;
    top: 48px;
    right: 0;
    bottom: 63px;
    width: 100%;
    overflow-y: auto;
}

.content-right .content-right-title {
    height: 48px;
    line-height: 48px;
    margin-left: 20px;
    margin-right: 20px;
    font-weight: 700;
    font-size: 16px;
    border-bottom: .8px solid var(--n-border-color);
}

.content-right .content-right-form {
    padding: 16px 20px 0px;
}

.content-right .content-right-auth {
    padding: 0 20px;
}

.content-right .content-right-bottom {
    position: absolute;
    bottom: 0;
    left: 1px;
    right: 0;
    padding: 14px 20px 14px;
    display: flex;
    justify-content: flex-end;
    border-top: 1px solid var(--n-border-color);
    background-color: var(--n-color);
}

.menu-icon-suffix-button {
    display: flex;
}

.menu-icon-suffix-button:hover {
    cursor: pointer;
}

.icon-table {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.icon-table .icon-unit {
    width: 38px;
    height: 38px;
    display: flex;
    justify-content: center;
    align-items: center;
    border: 1px solid var(--n-divider-color);
    font-size: 18px;
}

.icon-table .icon-unit:hover {
    cursor: pointer;
}
</style>